const fs = require('fs');
const URL = require('url');
const axios = require('axios');
const websocket = require("ws");

class Kook {

    guildList = [];
    wsClient = null;
    exit = false;
    SparkConfig = null;
    sn = 0;
    
    constructor(BOT_TOKEN, BOT_ID) {
        this.botID = BOT_ID;
        this.axios = axios.create({
            baseURL: 'https://www.kookapp.cn',
            params: {
                compress: 0
            },
            headers: {
                Authorization: `Bot ${BOT_TOKEN}`
            }
        });
        // this.getCommon('/guild/list')
        //     .then(res => this.guildList = res.items)
        //     .catch(err => console.log(err));
    };

    async getCommon(url, data) {
        return new Promise((resolve, reject) => {
            let timeOut = setTimeout(() => {
                console.log("[KOOK] GET Timeout.");
                reject(new TypeError("Type_Err: Not an Object."));
            }, 10000);
            if (typeof data != 'object' && data !== undefined)
                reject("Type_Err: Not an Object.")
            this.axios.get(`/api/v3${url}${URL.format({ query: data })}`).then((res, err) => {
                clearTimeout(timeOut);
                if (err)
                    reject(err);
                if (res.data.code)
                    reject(new Error('KookAPI_GET_Err with errcode:' + res.data.code + res.data.message));
                resolve(res.data.data);
            });
        });
    };
    async postCommon(url, data) {
        return new Promise((resolve, reject) => {
            let timeOut = setTimeout(() => {
                console.log("[KOOK] POST Timeout.");
                reject(new TypeError("Type_Err: Not an Object."));
            }, 10000);
            if (typeof data != 'object' && data !== undefined)
                reject("Type_Err: Not an Object.")
            this.axios.post('/api/v3' + url, data).then((res, err) => {
                clearTimeout(timeOut);
                if (err)
                    reject(err);
                if (res.data.code)
                    reject(new Error('KookAPI_GET_Err with errcode:' + res.data.code + res.data.message));
                resolve(res.data.data);
            });
        });
    };

    async sendMsg(msg, targetID) {
        return new Promise((resolve, reject) => {
            this.postCommon('/message/create', {
                type: 1,
                target_id: targetID,
                content: msg,
            })
                .then((res) => resolve(res))
                .catch((err) => reject(err));
        })
    };
    async multiSendMsg(msg, targetIDArr) {
        return new Promise((resolve, reject) => {
            Promise.all(targetIDArr.map((item) => {
                return this.sendMsg(msg, item);
            }))
                .then((res) => resolve(res))
                .catch((err) => reject(err));
        });
    };

    async sendCardMsg(msg, target_id) {
        return new Promise((resolve, reject) => {
            this.postCommon('/message/create', {
                type: 10,
                target_id: target_id,
                content: msg,
            })
                .then((res) => resolve(res))
                .catch((err) => reject(err));
        })
    };

    async getWsURL() {
        return new Promise((resolve, reject) => {
            this.getCommon('/gateway/index')
                .then(res => resolve(res.url))
                .catch(err => reject(err));
        })
    };

    async connectWebSocket(msgParse) {
        this.wsClient = new websocket(await this.getWsURL());
        this.wsClient.on('open', () => {
            this.wsHeartBeat = setInterval(() => {
                this.wsClient.send(JSON.stringify({ s: 2, sn: this.sn ?? 0 }));
            }, 30000);
            console.log('[KOOK] ws connected');
        });
        this.wsClient.on('close', () => {
            console.log('[KOOK] ws disconnected');
            clearInterval(this.wsHeartBeat);
            if (this.exit === false) {
                console.log('[KOOK] reconnecting...');
                this.wsClient = null;
                this.connectWebSocket();
            };
        });

        this.wsClient.on('message', res => {
            let data = JSON.parse(res);
            let heatBeatTimeout = null;
            // console.log('[KOOK] ws message: ' + JSON.stringify(data.d));

            switch (data.s) {
                case 0:// Message   server -> client
                    this.sn = data.sn;
                    msgParse(data.d);
                    break;
                case 1:// Hello     server -> client
                    break;
                case 2:// Ping      client -> server
                    heatBeatTimeout = setTimeout(() => {
                        console.log('[KOOK] HeartBeatTimeout');
                    }, 6000);
                    break;
                case 3:// Pong      server -> client
                    clearTimeout(heatBeatTimeout);
                    console.log('[KOOK] HeartBeatVerified, SN: ' + this.sn);
                case 4:
                    break;
                case 5:
                    console.log("five")
                    this.wsClient.close();
                    break;
                default:
                    console.log('[KOOK] NewMsg: ' + data.s);
            };
        });
    };

    async offLine() {
        await this.postCommon('/user/offline');
        console.log('offLine');
    };
}

module.exports = Kook;
